package com.powernode.dispatch.client;

import com.alibaba.fastjson.JSONObject;
import com.powernode.common.execption.PowerException;
import com.powernode.common.result.ResultCodeEnum;
import com.powernode.dispatch.config.XxlJobClientConfig;
import com.powernode.model.entity.dispatch.XxlJobInfo;
import jakarta.annotation.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;

/**
 * 动态操作xxl-job客户端类
 * 提供与XXL-Job调度中心交互的API，用于动态创建、管理定时任务
 */
@Slf4j
@Component
public class XxlJobClient {
    @Resource
    private XxlJobClientConfig xxlJobClientConfig;// 注入XXL-Job客户端配置类，包含连接调度中心的必要配置信息
    @Resource
    private RestTemplate restTemplate;// 注入RestTemplate，用于发送HTTP请求到XXL-Job调度中心

    /**
     * 动态添加XXL-Job定时任务
     *
     * @param executeHandler 执行器处理器名称，对应实际执行任务的方法名
     * @param param          任务执行参数
     * @param cron           任务调度表达式，定义任务执行的时间规则
     * @param desc           任务描述信息
     * @return 任务ID，如果添加失败可能返回null
     */
    public Long addJob(String executeHandler, String param, String cron, String desc) {
        // 创建任务信息对象，用于存储任务的各种配置
        XxlJobInfo xxlJobInfo = new XxlJobInfo();

        xxlJobInfo.setJobGroup(xxlJobClientConfig.getJobGroupId());// 设置任务分组ID，从配置中获取
        xxlJobInfo.setJobDesc(desc);// 设置任务描述信息
        xxlJobInfo.setAuthor("pat");// 设置任务负责人
        xxlJobInfo.setScheduleType("CRON");// 设置调度类型为CRON表达式
        xxlJobInfo.setScheduleConf(cron);// 设置具体的CRON表达式
        xxlJobInfo.setGlueType("BEAN");// 设置任务模式为BEAN模式（即执行器中注册的Bean方法
        xxlJobInfo.setExecutorHandler(executeHandler);// 设置执行器处理器名称
        xxlJobInfo.setExecutorParam(param);// 设置任务执行参数
        xxlJobInfo.setMisfireStrategy("FIRST");// 设置错过任务执行的策略
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION");// 设置任务阻塞处理策略为串行执行
        xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW");// 设置错过任务的执行策略为立即执行一次
        xxlJobInfo.setExecutorTimeout(0);// 设置任务执行超时时间（0表示不超时）
        xxlJobInfo.setExecutorFailRetryCount(0);// 设置任务失败重试次数（0表示不重试）

        // 创建HTTP请求头对象
        HttpHeaders httpHeaders = new HttpHeaders();
        // 设置请求内容类型为JSON格式
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        // 构建HTTP请求实体，包含任务信息对象和请求头
        HttpEntity<Object> entity = new HttpEntity<>(xxlJobInfo, httpHeaders);
        // 从配置中获取添加任务的API URL
        String addUrl = xxlJobClientConfig.getAddUrl();
        // 发送POST请求到XXL-Job调度中心，并指定响应类型为JSONObject
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(addUrl, entity, JSONObject.class);
        // 检查响应状态码是否为200（成功）
        if (response.getStatusCode().value() == 200) {
            // 如果请求成功，从响应体中获取任务ID并返回
            return response.getBody().getLong("content");
        }
        // 如果请求失败，抛出XXL-Job错误异常
        throw new PowerException(ResultCodeEnum.XXL_JOB_ERROR);
    }

    /**
     * 启动XXL-Job定时任务
     * @param jobId 任务ID，标识需要启动的具体任务
     * @return 布尔值，表示任务启动是否成功
     * @throws PowerException 当启动任务失败时抛出异常
     */
    public Boolean startJob(Long jobId) {
        // 创建任务信息对象，仅用于传递任务ID
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        // 设置任务ID（注意：这里将Long类型转换为int类型，对于大数值可能存在溢出风险）
        xxlJobInfo.setId(jobId.intValue());
        // 创建HTTP请求头对象
        HttpHeaders httpHeaders = new HttpHeaders();
        // 设置请求内容类型为JSON格式
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        // 构建HTTP请求实体，包含任务信息对象和请求头
        HttpEntity<Object> entity = new HttpEntity<>(xxlJobInfo, httpHeaders);
        // 从配置中获取启动任务的API URL（已修正为正确的启动URL）
        String startJobUrl = xxlJobClientConfig.getStartJobUrl();
        // 发送POST请求到XXL-Job调度中心，请求启动指定任务
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(startJobUrl, entity, JSONObject.class);
        // 检查响应状态码是否为200（成功）
        if (response.getStatusCode().value() == 200) {
            // 如果请求成功，返回true表示任务启动成功
            return true;
        }
        // 如果请求失败，抛出XXL-Job错误异常
        throw new PowerException(ResultCodeEnum.XXL_JOB_ERROR);
    }

    /**
     * 停止XXL-Job调度任务
     * @param jobId 任务ID
     * @return 操作结果，成功返回true
     * @throws PowerException 当XXL-Job操作失败时抛出异常
     */
    public Boolean stopJob(Long jobId) {
        // 创建任务信息对象并设置任务ID
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        // 将Long类型的jobId转为int类型（注意：这里可能存在数值溢出风险，XXL-Job的ID不应该超过int的范围）
        xxlJobInfo.setId(jobId.intValue());

        // 设置HTTP请求头，指定内容类型为JSON
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 构建HTTP请求实体，包含任务信息
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        // 获取停止任务的URL
        String url = xxlJobClientConfig.getStopJobUrl();
        // 发送POST请求到XXL-Job调度中心停止任务
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);
        // 检查响应状态码和业务处理码
        if(response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
            // 记录成功日志
            log.info("停止xxl执行任务成功:{},返回信息:{}", jobId, response.getBody().toJSONString());
            return true;
        }
        // 记录失败日志
        log.info("停止xxl执行任务失败:{},返回信息:{}", jobId, response.getBody().toJSONString());
        // 抛出XXL-Job操作失败异常
        throw new PowerException(ResultCodeEnum.XXL_JOB_ERROR);
    }

    /**
     * 删除XXL-Job调度任务
     * @param jobId 任务ID
     * @return 操作结果，成功返回true
     * @throws PowerException 当XXL-Job操作失败时抛出异常
     */
    public Boolean removeJob(Long jobId) {
        // 创建任务信息对象并设置任务ID
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        // 将Long类型的jobId转为int类型（注意：这里可能存在数值溢出风险）
        xxlJobInfo.setId(jobId.intValue());

        // 设置HTTP请求头，指定内容类型为JSON
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 构建HTTP请求实体，包含任务信息
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        // 获取删除任务的URL
        String url = xxlJobClientConfig.getRemoveUrl();
        // 发送POST请求到XXL-Job调度中心删除任务
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);
        // 检查响应状态码和业务处理码
        if(response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
            // 记录成功日志
            log.info("删除xxl执行任务成功:{},返回信息:{}", jobId, response.getBody().toJSONString());
            return true;
        }
        // 记录失败日志
        log.info("删除xxl执行任务失败:{},返回信息:{}", jobId, response.getBody().toJSONString());
        // 抛出XXL-Job操作失败异常
        throw new PowerException(ResultCodeEnum.XXL_JOB_ERROR);
    }

    /**
     * 添加并立即启动XXL-Job调度任务
     * @param executorHandler 执行器处理器名称（Bean名称）
     * @param param 任务参数
     * @param corn 定时表达式
     * @param desc 任务描述
     * @return 添加成功的任务ID
     * @throws PowerException 当XXL-Job操作失败时抛出异常
     */
    public Long addAndStart(String executorHandler, String param, String corn, String desc) {
        // 创建任务信息对象并设置各项任务属性
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        xxlJobInfo.setJobGroup(xxlJobClientConfig.getJobGroupId()); // 任务分组ID
        xxlJobInfo.setJobDesc(desc); // 任务描述
        xxlJobInfo.setAuthor("pat"); // 作者
        xxlJobInfo.setScheduleType("CRON"); // 调度类型为CRON表达式
        xxlJobInfo.setScheduleConf(corn); // 调度表达式
        xxlJobInfo.setGlueType("BEAN"); // 任务类型为Bean
        xxlJobInfo.setExecutorHandler(executorHandler); // 执行器处理器
        xxlJobInfo.setExecutorParam(param); // 执行参数
        xxlJobInfo.setExecutorRouteStrategy("FIRST"); // 执行器路由策略：第一个
        xxlJobInfo.setExecutorBlockStrategy("SERIAL_EXECUTION"); // 阻塞策略：串行执行
        xxlJobInfo.setMisfireStrategy("FIRE_ONCE_NOW"); // 错过执行策略：立即执行一次
        xxlJobInfo.setExecutorTimeout(0); // 执行超时时间：0表示不超时
        xxlJobInfo.setExecutorFailRetryCount(0); // 失败重试次数：0表示不重试

        // 设置HTTP请求头，指定内容类型为JSON
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 构建HTTP请求实体，包含完整的任务信息
        HttpEntity<XxlJobInfo> request = new HttpEntity<>(xxlJobInfo, headers);

        // 获取添加并启动任务的URL
        String url = xxlJobClientConfig.getAddAndStartUrl();
        // 发送POST请求到XXL-Job调度中心添加并启动任务
        ResponseEntity<JSONObject> response = restTemplate.postForEntity(url, request, JSONObject.class);
        // 检查响应状态码和业务处理码
        if(response.getStatusCode().value() == 200 && response.getBody().getIntValue("code") == 200) {
            // 记录成功日志
            log.info("增加并开始执行xxl任务成功,返回信息:{}", response.getBody().toJSONString());
            // 从响应中获取任务ID并返回（content字段为任务id）
            return response.getBody().getLong("content");
        }
        // 记录失败日志
        log.info("增加并开始执行xxl任务失败:{}", response.getBody().toJSONString());
        // 抛出XXL-Job操作失败异常
        throw new PowerException(ResultCodeEnum.XXL_JOB_ERROR);
    }
}
